package services

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"

	"jianianhua-server/config"
	"jianianhua-server/database"
	"jianianhua-server/models"

	"github.com/golang-jwt/jwt/v5"
	"gorm.io/gorm"
)

// WechatService 微信服务
type WechatService struct{
	config *config.Config
}

// NewWechatService 创建微信服务实例
func NewWechatService(cfg *config.Config) *WechatService {
	return &WechatService{
		config: cfg,
	}
}

// WechatLoginRequest 微信登录请求
type WechatLoginRequest struct {
	Code     string                 `json:"code" binding:"required"`
	UserInfo map[string]interface{} `json:"userInfo"`
}

// WechatLoginResponse 微信登录响应
type WechatLoginResponse struct {
	Token    string             `json:"token"`
	User     *models.User `json:"user"`
	ExpiresIn int64             `json:"expires_in"`
}

// WechatSessionResponse 微信会话响应
type WechatSessionResponse struct {
	OpenID     string `json:"openid"`
	SessionKey string `json:"session_key"`
	UnionID    string `json:"unionid"`
	ErrCode    int    `json:"errcode"`
	ErrMsg     string `json:"errmsg"`
}

// Login 微信登录
func (s *WechatService) Login(req WechatLoginRequest) (*WechatLoginResponse, error) {
	// 获取微信会话信息
	sessionResp, err := s.getWechatSession(req.Code)
	if err != nil {
		return nil, fmt.Errorf("获取微信会话失败: %v", err)
	}

	if sessionResp.ErrCode != 0 {
		return nil, fmt.Errorf("微信接口错误: %s", sessionResp.ErrMsg)
	}

	// 查找或创建用户
	user, err := s.findOrCreateUser(sessionResp.OpenID, sessionResp.SessionKey, req.UserInfo)
	if err != nil {
		return nil, fmt.Errorf("用户处理失败: %v", err)
	}

	// 检查用户ID是否有效
	if user.ID == 0 {
		// 重新查询用户
		var freshUser models.User
		if err := database.DB.Where("openid = ?", user.OpenID).First(&freshUser).Error; err != nil {
			return nil, fmt.Errorf("用户查询失败: %v", err)
		}
		user = &freshUser
	}

	// 生成JWT token
	token, expiresIn, err := s.GenerateToken(user.ID, user.Role)
	if err != nil {
		return nil, fmt.Errorf("生成token失败: %v", err)
	}

	return &WechatLoginResponse{
		Token:     token,
		User:      user,
		ExpiresIn: expiresIn,
	}, nil
}

// getWechatSession 获取微信会话信息
func (s *WechatService) getWechatSession(code string) (*WechatSessionResponse, error) {
	url := fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
		s.config.WechatAppID, s.config.WechatSecret, code)

	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var sessionResp WechatSessionResponse
	if err := json.Unmarshal(body, &sessionResp); err != nil {
		return nil, err
	}

	return &sessionResp, nil
}

// findOrCreateUser 查找或创建用户
func (s *WechatService) findOrCreateUser(openID, sessionKey string, userInfo map[string]interface{}) (*models.User, error) {
	var wechatUser models.User

	// 先查找未删除的用户
	err := database.DB.Where("openid = ?", openID).First(&wechatUser).Error
	if err != nil {
		// 检查是否是记录不存在的错误
		if err.Error() != "record not found" {
			return nil, fmt.Errorf("查询用户失败: %v", err)
		}
		
		// 未找到未删除的用户，检查是否存在被软删除的用户
		var deletedUser models.User
		err = database.DB.Unscoped().Where("openid = ?", openID).First(&deletedUser).Error
		if err == nil {
			// 存在被软删除的用户，恢复它
			wechatUser = deletedUser
			wechatUser.DeletedAt = gorm.DeletedAt{} // 清除软删除标记
			wechatUser.SessionKey = sessionKey
			wechatUser.Status = 1 // 恢复状态
		} else {
			// 完全不存在，创建新用户
			wechatUser = models.User{
				OpenID:     openID,
				SessionKey: sessionKey,
				Nickname:   "微信用户",
				Avatar:     "",
				Gender:     0,
				Phone:      nil, // 使用nil，避免空字符串的唯一约束冲突
				Role:       "user",
				Status:     1,
			}
		}

		// 更新微信用户信息
		if userInfo != nil {
			if name, ok := userInfo["nickName"].(string); ok && name != "" {
				wechatUser.Nickname = name
			}
			if avatarUrl, ok := userInfo["avatarUrl"].(string); ok && avatarUrl != "" {
				wechatUser.Avatar = avatarUrl
			}
			if sex, ok := userInfo["gender"].(float64); ok {
				wechatUser.Gender = int(sex)
			}
			if country, ok := userInfo["country"].(string); ok {
				wechatUser.Country = country
			}
			if province, ok := userInfo["province"].(string); ok {
				wechatUser.Province = province
			}
			if city, ok := userInfo["city"].(string); ok {
				wechatUser.City = city
			}
			if language, ok := userInfo["language"].(string); ok {
				wechatUser.Language = language
			}
		}

		// 保存用户（创建或恢复）
		if err := database.DB.Save(&wechatUser).Error; err != nil {
			return nil, fmt.Errorf("保存用户失败: %v", err)
		}
	} else {
		// 更新现有用户的session_key和用户信息
		wechatUser.SessionKey = sessionKey
		
		// 更新微信用户信息
		if userInfo != nil {
			if name, ok := userInfo["nickName"].(string); ok && name != "" {
				wechatUser.Nickname = name
			}
			if avatarUrl, ok := userInfo["avatarUrl"].(string); ok && avatarUrl != "" {
				wechatUser.Avatar = avatarUrl
			}
			if sex, ok := userInfo["gender"].(float64); ok {
				wechatUser.Gender = int(sex)
			}
			if country, ok := userInfo["country"].(string); ok {
				wechatUser.Country = country
			}
			if province, ok := userInfo["province"].(string); ok {
				wechatUser.Province = province
			}
			if city, ok := userInfo["city"].(string); ok {
				wechatUser.City = city
			}
			if language, ok := userInfo["language"].(string); ok {
				wechatUser.Language = language
			}
		}
		
		// 尝试保存更新，如果失败就忽略错误
		database.DB.Save(&wechatUser)
	}

	return &wechatUser, nil
}

// GenerateToken 生成JWT token
func (s *WechatService) GenerateToken(userID uint, role string) (string, int64, error) {
	expiresIn := int64(7 * 24 * 60 * 60) // 7天
	expiresAt := time.Now().Add(time.Duration(expiresIn) * time.Second)

	claims := jwt.MapClaims{
		"user_id": userID,
		"role":    role,
		"exp":     expiresAt.Unix(),
		"iat":     time.Now().Unix(),
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenString, err := token.SignedString([]byte(s.config.JWTSecret))
	if err != nil {
		return "", 0, err
	}

	return tokenString, expiresIn, nil
}

// ValidateToken 验证JWT token
func (s *WechatService) ValidateToken(tokenString string) (*jwt.MapClaims, error) {
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(s.config.JWTSecret), nil
	})

	if err != nil {
		return nil, err
	}

	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		return &claims, nil
	}

	return nil, fmt.Errorf("invalid token")
}